package 剑指offer;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author zhangmin
 * @create 2021-11-15 11:38
 *
 * 4.查找算法
 * ==map||set||二分查找
 */
public class day4_03_531_532 {
    /**===========================================================================================================================
     * 剑指 Offer 03. 数组中重复的数字
     * 找出数组中重复的数字。在一个长度为 n 的数组 nums 里的所有数字都在 0～n-1 的范围内。数组中某些数字是重复的，
     * 但不知道有几个数字重复了，也不知道每个数字重复了几次。请找出数组中《任意一个》重复的数字。
     * 1.map存储
     * 2.用set判断
     * */
    public int findRepeatNumber1(int[] nums) {
        Map<Integer,Integer> map=new HashMap<>();
        for (int n:nums) {
            if (map.containsKey(n))return n;
            map.put(n,map.getOrDefault(n,0)+1);
        }
        return -1;
    }
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set=new HashSet<>();
        for (int n:nums) {
            if (!set.add(n)) return n;
        }
        return -1;
    }


    /**===========================================================================================================================
     * 剑指 Offer 53 - I. 在排序数组中查找数字 I
     * 统计一个数字在排序数组中出现的次数。
     * 1.挨个判断
     * 2.二分查找，找到左边界后右边界，相减得到
     * */
    public int search1(int[] nums, int target) {
        int count=0;
        for (int num:nums) {
            if (num==target) count++;
        }
        return count;
    }
    //二分查找，当lower为true时查找左边界，为false时查找右边界
    public int binarySearch(int[] nums,int target,boolean lower){
        int letf=0,right=nums.length-1;
        int res=nums.length;
        while (letf<=right){
            int mid=letf+(right-letf)/2;
            if (nums[mid]>target||(lower&&nums[mid]>=target)){
                right=mid-1;
                res=mid;
            }else {
                letf=mid+1;
            }
        }
        return res;
    }
    public int search(int[] nums, int target) {
        int l=binarySearch(nums,target,true);
        int r=binarySearch(nums,target,false)-1;
        if (l<r&&r<nums.length&&nums[l]==target&&nums[r]==target){
            return r-l+1;
        }
        return 0;
    }

    /**===========================================================================================================================
     * 剑指 Offer 53 - II. 0～n-1中缺失的数字
     * 一个长度为n-1的递增排序数组中的所有数字都是唯一的，并且每个数字都在范围0～n-1之内。在范围0～n-1内的n个数字中有且只有一个数字不在该数组中，请找出这个数字。
     * 二分查找，确实数字之后的所有元素都比他的下标大
     * */
    public int missingNumber(int[] nums) {
        int left=0,right=nums.length-1;
        while (left<=right){
            int mid=left+(right-left)/2;
            if (nums[mid]>mid){
                right=mid-1;
            }else if (nums[mid]==mid){
                left=mid+1;
            }
        }
        return left;
    }



}
